package cc.rengu.igas.bsps.core.service.trans;

import cc.rengu.igas.acct.facade.request.VirtAcctBalanceQueryRequest;
import cc.rengu.igas.acct.facade.request.VirtAcctPreAuthRequest;
import cc.rengu.igas.acct.facade.response.VirtAcctBalanceQueryResponse;
import cc.rengu.igas.acct.facade.response.VirtAcctPreAuthResponse;
import cc.rengu.igas.acct.facade.result.Result;
import cc.rengu.igas.bsps.common.constant.BspsAppParamConstant;
import cc.rengu.igas.bsps.common.constant.DubboMethodConstant;
import cc.rengu.igas.bsps.common.dao.BspsMchntAcctInfoMapper;
import cc.rengu.igas.bsps.common.dao.BspsMchntFeeInfoMapper;
import cc.rengu.igas.bsps.common.dao.BspsUserInfoMapper;
import cc.rengu.igas.bsps.common.dao.impl.BspsMchntAcctInfoMapperImpl;
import cc.rengu.igas.bsps.common.dao.impl.BspsMchntFeeInfoMapperImpl;
import cc.rengu.igas.bsps.common.dao.impl.BspsUserInfoMapperImpl;
import cc.rengu.igas.bsps.common.entity.MchntAcctInfo;
import cc.rengu.igas.bsps.common.entity.MchntFeeInfo;
import cc.rengu.igas.bsps.common.entity.RoleAcctInfo;
import cc.rengu.igas.bsps.common.entity.UserInfo;
import cc.rengu.igas.bsps.common.enums.BspsPayTypeEnum;
import cc.rengu.igas.bsps.common.enums.FeeTypeEnum;
import cc.rengu.igas.bsps.common.enums.MchntTypeEnum;
import cc.rengu.igas.bsps.common.enums.RespCodeEnum;
import cc.rengu.igas.bsps.core.model.AcctInfo;
import cc.rengu.igas.bsps.core.model.UserSessionInfo;
import cc.rengu.igas.bsps.core.realize.PublicDealService;
import cc.rengu.igas.bsps.core.realize.TransSuccessHandleService;
import cc.rengu.igas.bsps.core.realize.impl.PublicDealServiceImpl;
import cc.rengu.igas.bsps.core.realize.impl.TransSuccessHandleServiceImpl;
import cc.rengu.igas.bsps.core.service.base.PayService;
import cc.rengu.igas.bsps.facade.base.Header;
import cc.rengu.igas.bsps.facade.request.MchntCashWithdrawalRequest;
import cc.rengu.igas.bsps.facade.response.MchntCashWithdrawalResponse;
import cc.rengu.igas.share.common.enums.SettleAcctTypeEnum;
import cc.rengu.igas.share.common.util.GlobalEsbUtil;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.SysParamMapper;
import cc.rengu.oltp.service.common.dao.impl.SysParamMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.PasswordInfo;
import cc.rengu.oltp.service.realize.*;
import cc.rengu.oltp.service.realize.impl.*;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.base.TimeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * 虚拟账户余额提现.
 */
public class MchntCashWithdrawalService extends PayService {

    @Override
    protected Object bizBeforeCust() throws Exception {
        MchntCashWithdrawalRequest mchntCashWithdrawalRequest = new MchntCashWithdrawalRequest();
        ConvertUtil.convertOutput(mchntCashWithdrawalRequest);

        List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList();
        if (CollectionUtils.isEmpty(channelCallCfgList)) {
            rglog.error("通道服务调用配置表无数据！,instId:<{}>,traceNo:<{}>,",
                    mchntCashWithdrawalRequest.getHeader().getInstId(), mchntCashWithdrawalRequest.getHeader().getTraceNo());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }

        ConvertUtil.convertInput(mchntCashWithdrawalRequest);
        return mchntCashWithdrawalRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        MchntCashWithdrawalRequest mchntCashWithdrawalRequest = (MchntCashWithdrawalRequest) request;
        String instId = mchntCashWithdrawalRequest.getHeader().getInstId();
        String mchntNo = mchntCashWithdrawalRequest.getMchntNo();
        String orderAmt = mchntCashWithdrawalRequest.getOrderAmt();
        String transPassword = mchntCashWithdrawalRequest.getTransPassword();
        String traceNo = mchntCashWithdrawalRequest.getHeader().getTraceNo();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        String chanlId = mchntCashWithdrawalRequest.getHeader().getChanlId();

        /* 校验交易密码 */
        //查询
        BspsUserInfoMapper bspsUserInfoMapper = new BspsUserInfoMapperImpl();
        UserInfo userInfo = bspsUserInfoMapper.selectBspsUserInfoByUserId(instId, mchntCashWithdrawalRequest.getUserId());
        if (userInfo == null) {
            rglog.error("用户不存在", mchntCashWithdrawalRequest.getUserId(), traceNo);
            throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_PASSWORD_ERROR.getRespDesc());
        }

        SafeKeyBoardService safeKeyBoardService = new SafeKeyBoardServiceImpl();
        if (chanlId.equals("PCWEB")) {
            Header header = mchntCashWithdrawalRequest.getHeader();
            UserSessionInfo keySessionInfo = JSON.parseObject(RedisUtil.onceGet(header.getSession()), UserSessionInfo.class);
            String randomString = keySessionInfo.getRandomString();
            keySessionInfo.setRandomString("");
            RedisUtil.onceSet(header.getSession(), JSONObject.toJSONString(keySessionInfo), BspsAppParamConstant.SESSION_EFFECTIVE_TIME);

            PasswordInfo passwordInfo = new PasswordInfo(mchntCashWithdrawalRequest.getMchntNo(), PinTypeEnum.DIGITAL, transPassword);
            transPassword = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
            if (!transPassword.equals(userInfo.getTransPassword())) {
                rglog.error("交易密码校验失败！拒绝提现请求！userId:<{}>，前端流水号：<{}>", mchntCashWithdrawalRequest.getUserId(), traceNo);
                throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_PASSWORD_ERROR.getRespDesc());
            }

        } else {
            PasswordInfo passwordInfo = new PasswordInfo(mchntNo, PinTypeEnum.DIGITAL, transPassword);
            transPassword = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
            if (!transPassword.equals(userInfo.getTransPassword())) {
                rglog.error("交易密码校验失败！拒绝提现请求！userId:<{}>，前端流水号：<{}>", mchntCashWithdrawalRequest.getUserId(), traceNo);
                throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_PASSWORD_ERROR.getRespDesc());
            }

        }
        rglog.error("=======提现==========密碼校验通过=======================================");

        rglog.debug("入参订单金额：{}", orderAmt);
        try {
            orderAmt = AmountUtil.checkAmt(orderAmt, 2, false, false);
            mchntCashWithdrawalRequest.setOrderAmt(orderAmt);
        } catch (Exception e) {
            rglog.error("订单金额非法.");
            throw new BizException(RespCodeEnum.AMOUNT_IS_UN_NORMAL.getRespCode(), RespCodeEnum.AMOUNT_IS_UN_NORMAL.getRespDesc());
        }
        //最低提现金额
        String cashWithdrawalMinAmt = BspsAppParamConstant.CASH_WITHDRAWAL_MIN_AMT;
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(instId, BspsAppParamConstant.MCHNT_PARAM_TYPE, BspsAppParamConstant.SYS_PARAM_TYPE_CASH_WITHDRAWAL_MIN_AMT);
        if (null != sysParam) {
            cashWithdrawalMinAmt = sysParam.getParamValue();
        }
        if (1 == AmountUtil.compare(cashWithdrawalMinAmt, orderAmt)) {
            rglog.error("提现金额<{}>低于最低提现金额<{}>", orderAmt, cashWithdrawalMinAmt);
            throw new BizException(RespCodeEnum.AMOUNT_IS_UN_NORMAL.getRespCode(), "提现金额低于最低提现金额:" + cashWithdrawalMinAmt);
        }

        /*step1:黑名单商户校验*/
        MchntService mchntService = new MchntServiceImpl();
//        mchntService.checkMchntBlackInfo(instId, mchntNo);

        /*step2:不允许提现检查*/
        MchntInfo mchntInfo = mchntService.getMchntInfo(instId, mchntNo);
        if (null == mchntInfo) {
            rglog.error("获取商户信息失败,mchntNo:<{}>", mchntNo);
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }
        if (!BspsAppParamConstant.FLAG_Y.equals(mchntInfo.getCashWithdrawalFlag())) {
            rglog.error("该商户未开通提现！拒绝提现请求！userId:<{}>，前端流水号：<{}>", mchntCashWithdrawalRequest.getUserId(), traceNo);
            throw new BizException(RespCodeEnum.MCHNT_NO_CASH_PERMISSION.getRespCode(), RespCodeEnum.MCHNT_NO_CASH_PERMISSION.getRespDesc());
        }

        if (MchntTypeEnum.CHAIN_MCHNT_STORE.getMchntType().equals(mchntInfo.getMchntType())) {
            rglog.error("连锁商户门店不允许提现.");
            throw new BizException(RespCodeEnum.CHAIN_MCHNT_STORE_CANNOT_OPERATE.getRespCode(), RespCodeEnum.CHAIN_MCHNT_STORE_CANNOT_OPERATE.getRespDesc());
        }

        /*step3:查询商户结算账户信息*/
        BspsMchntAcctInfoMapper bspsMchntAcctInfoMapper = new BspsMchntAcctInfoMapperImpl();
        MchntAcctInfo mchntAcctInfo = bspsMchntAcctInfoMapper.selectBspsMchntAcctInfoByPrimaryKey(instId, mchntNo, "*", "00");
        if (null == mchntAcctInfo) {
            rglog.error("商户结算账户信息查询失败！拒绝提现请求！userId:<{}>，前端流水号：<{}>,mchntNo:<{}>", mchntCashWithdrawalRequest.getUserId(), traceNo, mchntNo);
            throw new BizException(RespCodeEnum.MCHNT_SETTLE_ACCT_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_SETTLE_ACCT_NOT_FOUND.getRespDesc());
        }

        String payType;
        //判断本行/他行
        if (mchntAcctInfo.getSettleAcctType().startsWith("0")) {
            /* 本行卡 */
            payType = BspsPayTypeEnum.BANK_CARD_PAY.getPayType();
        } else {
            /* 他行卡 */
            payType = BspsPayTypeEnum.OTHER_BANK_CARD_PAY.getPayType();
        }
        /* 获取机构内部户 提现/D0（本行）： 垫资户  */
        SettleAcctTypeEnum settleAcctTypeEnum = SettleAcctTypeEnum.DZ_SUBJECT;
        PublicDealService publicDealService = new PublicDealServiceImpl();
        RoleAcctInfo roleAcctInfo = publicDealService.getInnerAccountByCondition(instId, settleAcctTypeEnum);
        if (null == roleAcctInfo) {
            rglog.error("机构内部户信息查询失败！拒绝提现请求！userId:<{}>，sysSeqNum：<{}>,mchntNo:<{}>", mchntCashWithdrawalRequest.getUserId(), sysSeqNum, mchntNo);
            throw new BizException(RespCodeEnum.INST_SETTLE_ACCT_NOT_FOUND.getRespCode(), RespCodeEnum.INST_SETTLE_ACCT_NOT_FOUND.getRespDesc());
        }

        /* step3：查询虚拟账户余额,连锁商户门店非独立维护的根据连锁商户号查 */
        VirtAcctBalanceQueryResponse virtAcctBalanceQueryResponse = queryVirtAcctBalance(mchntCashWithdrawalRequest);
        rglog.info("虚拟账户余额<{}>,可用余额<{}>", virtAcctBalanceQueryResponse.getAcctBalance(), virtAcctBalanceQueryResponse.getAvailableBalance());
        if (1 == AmountUtil.compare(cashWithdrawalMinAmt, virtAcctBalanceQueryResponse.getAvailableBalance())) {
            rglog.error("可用余额<{}>低于最低提现金额<{}>", virtAcctBalanceQueryResponse.getAvailableBalance(), cashWithdrawalMinAmt);
            throw new BizException(RespCodeEnum.WITHDRAWAL_AMT_OVER_LIMIT.getRespCode(), RespCodeEnum.WITHDRAWAL_AMT_OVER_LIMIT.getRespDesc());
        }

        /*计算商户手续费商户*/
        String mchntFee = getRealMchntFee(mchntCashWithdrawalRequest, virtAcctBalanceQueryResponse.getAvailableBalance());

        //初始化用户订单信息
        UserOrderInfo userOrderInfo = initUserOrderInfo(mchntCashWithdrawalRequest, orderAmt, sysSeqNum);
        //初始化商户订单信息
        MchntOrderInfo mchntOrderInfo = initMchntOrderInfo(mchntCashWithdrawalRequest, xmlTreeUtil, orderAmt, mchntFee, virtAcctBalanceQueryResponse.getAvailableBalance());
        //初始化 虚拟账户预授权-支付订单信息
        PayOrderInfo virtPreAuthPayOrderInfo = initAcctPayOrderInfo(orderAmt, sysSeqNum, mchntOrderInfo.getRealSettleAmt(), "1", mchntAcctInfo, ChannelEnum.ACCT.getChannelType());

        //新增订单信息
        OrderService orderService = new OrderServiceImpl();
        boolean dbResult = orderService.registerOrderInfo(userOrderInfo, Arrays.asList(mchntOrderInfo), virtPreAuthPayOrderInfo);
        if (!dbResult) {
            rglog.error("新增用户订单，商户订单，支付订单失败，提现交易失败！instId:<{}>，sysSeqNum：<{}>", instId, sysSeqNum);
            throw new BizException(RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespCode(), RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespDesc());
        }

        /* step5:调用虚拟账户接口进行预授权处理 */
        acctPreAuth(mchntCashWithdrawalRequest, sysSeqNum, userOrderInfo, mchntOrderInfo, virtPreAuthPayOrderInfo);

        /* step6：新增 ESB提现-支付订单 */
        PayOrderInfo esbCashPayOrderInfo = initEsbPayOrderInfo(mchntOrderInfo, payType, roleAcctInfo, mchntAcctInfo);
        dbResult = orderService.registerOrderInfo(null, null, esbCashPayOrderInfo);
        if (!dbResult) {
            rglog.error("新增用户订单，商户订单，支付订单失败，提现交易失败！instId:<{}>，sysSeqNum：<{}>", instId, sysSeqNum);
            throw new BizException(RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespCode(), RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespDesc());
        }

        /* step7：调用ESB进行提现 */
        return mchntCash(mchntCashWithdrawalRequest, userOrderInfo, mchntOrderInfo, esbCashPayOrderInfo);
    }

    /**
     * 计算手续费
     */
    private String getRealMchntFee(MchntCashWithdrawalRequest mchntCashWithdrawalRequest, String acctAvailableBalance) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        /*费率*/
        String feeRate = getFeeRate();
        xmlTreeUtil.setXmlTreeStringValue("feeRate", feeRate);
        /*最多提现金额*/
        BigDecimal bFeeRate = new BigDecimal(feeRate);
        String maxWithdrawAmt = AmountUtil.division(acctAvailableBalance, bFeeRate.add(new BigDecimal("1")).toString(), 6);
        //比如账户余额100.008,上方算出最大提现金额100.006,如果提现金额四舍五入(100.01),就超过了余额,再加上手续费,肯定超出了余额,所以金额进行取小,舍去小数点两位以后
        int dotIndex = maxWithdrawAmt.indexOf(".");
        maxWithdrawAmt = maxWithdrawAmt.substring(0, dotIndex + 3);
        rglog.debug("最多提现金额<{}>,上送订单金额<{}>", maxWithdrawAmt, mchntCashWithdrawalRequest.getOrderAmt());
        if (AmountUtil.compare(mchntCashWithdrawalRequest.getOrderAmt(), maxWithdrawAmt) >= 0) {
            //提现金额大于最大提现金额
            mchntCashWithdrawalRequest.setOrderAmt(maxWithdrawAmt);
        }

        //比如账户余额100.149,如果算出最大提现金额100.000,则收手续费(0.149),即以100.000计算手续费为0.149
        // 如果用multiplication(String amt1,String amt2,int scale)计算手续费,得出手续费为0.15,加上提现金额(100.00)后(100.15)超过余额(100.149)
        // 所以要用multiplication(String amt1,String amt2)计算后,再AmountUtil.multiplication(mchntFee, "1", 3)保留两位位,舍去之后的金额
        String mchntFee = AmountUtil.multiplication(mchntCashWithdrawalRequest.getOrderAmt(), feeRate);
        mchntFee = AmountUtil.multiplication(mchntFee, "1", 2);
        rglog.debug("算得手续费:<{}>", mchntFee);
        return mchntFee;
    }

    private String getFeeRate() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        String mchntNo = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MCHNT_NO);

        /* 计算提现手续费  */
        BspsMchntFeeInfoMapper bspsMchntFeeInfoMapper = new BspsMchntFeeInfoMapperImpl();
        String date = DateUtil.getCurrentDate();
        MchntFeeInfo mchntFeeInfo = bspsMchntFeeInfoMapper.selectBspsMchntFeeInfoByPrimaryKey(instId, mchntNo, BaseProdEnum.BASIC.getProdCode(), FeeTypeEnum.DO.getFeeType(), date);

        String feeRate;
        if (null == mchntFeeInfo) {
            rglog.info("根据机构号:<{}>，商户号：<{}>查询商户提现费率为空!，查询该机构的默认费率设置。", instId, mchntNo);
            SysParamMapper sysParamMapper = new SysParamMapperImpl();
            SysParam sysParam = sysParamMapper.selectSysParamByPrimaryKey(instId, BspsAppParamConstant.MCHNT_PARAM_TYPE, BspsAppParamConstant.DEFAULT_D0_FEE);
            if (null == sysParam) {
                rglog.error("根据机构号:<{}>,查询系统参数信息表机构默认提现费率信息失败!", instId);
                throw new BizException(RespCodeEnum.QUERY_NULL.getRespCode(), RespCodeEnum.QUERY_NULL.getRespDesc());
            }
            feeRate = sysParam.getParamValue();
        } else {
            feeRate = mchntFeeInfo.getFeeRate();
        }
        //费率以千分之几存储  千分之一 存储为 1.000
        feeRate = AmountUtil.multiplication(feeRate, "0.001", 3);
        rglog.debug("商户提现费率<{}>", feeRate);
        return feeRate;
    }

    private String getPayType(String mchntNo, String sysSeqNum, MchntAcctInfo mchntAcctInfo) throws Exception {
        BinInfoService binInfoService = new BinInfoServiceImpl();
        BinInfo binInfo = binInfoService.getCardBinInfo(mchntAcctInfo.getSettleAcctNo());
        if (null == binInfo) {
            rglog.error("通过结算卡号查询卡bin信息为空！提现失败 sysSeqNum：<{}>,mchntNo:<{}>,acctNo:<{}>", sysSeqNum, mchntNo, mchntAcctInfo.getSettleAcctNo());
            throw new BizException(RespCodeEnum.GET_CARD_BIN_INFO_ERROR.getRespCode(), RespCodeEnum.GET_CARD_BIN_INFO_ERROR.getRespDesc());
        }

        //查询该法人行的银联机构号
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(mchntAcctInfo.getInstId(), BspsAppParamConstant.MCHNT_PARAM_TYPE, BspsAppParamConstant.CUPS_INSR_ID);

        String payType;
        if (binInfo.getIssuerCode().substring(0, 4).equals(sysParam.getParamValue().substring(0, 4))) {
            /* 本行卡 */
            payType = BspsPayTypeEnum.BANK_CARD_PAY.getPayType();
        } else {
            /* 他行卡 */
            payType = BspsPayTypeEnum.OTHER_BANK_CARD_PAY.getPayType();
        }
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.PAY_TYPE, payType);

        return payType;
    }

    //region 初始化订单信息

    private PayOrderInfo initAcctPayOrderInfo(String orderAmt, String sysSeqNum, String realPayAmt, String dstCallIndex, MchntAcctInfo mchntAcctInfo, String channelType) throws Exception {
        Optional<ChannelCallCfg> channelCallCfgOptional = txnInfo.getChannelCallCfgList().stream()
                .filter(item -> ChannelEnum.ACCT.getChannelType().equals(channelType) && dstCallIndex.equals(item.getCallIndex())).findFirst();

        if (!channelCallCfgOptional.isPresent()) {
            rglog.error("通道服务调用配置表无序号为{}的数据！,sysSeqNum:<{}>,",
                    dstCallIndex, sysSeqNum);
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        //获取通道服务调用配置
        ChannelCallCfg channelCallCfg = channelCallCfgOptional.get();

        PayOrderInfo payOrderInfo = new PayOrderInfo();
        ConvertUtil.convertOutput(payOrderInfo);
        payOrderInfo.setSysSeqNum(sysSeqNum);
        payOrderInfo.setMchntOrderId(sysSeqNum);
        payOrderInfo.setOrderAmt(orderAmt);
        payOrderInfo.setRealPayAmt(realPayAmt);
        //交易通道标识
        payOrderInfo.setMsgDstId(channelCallCfg.getCallChannelId());
        //支付通道流水号
        String channelSeqNum = sysSeqNum + dstCallIndex;
        payOrderInfo.setChannelSeqNum(channelSeqNum);
        //虚拟账户 支付通道对账唯一KEY  虚拟账户：系统流水号+调用序号
        payOrderInfo.setChannelReconKey(channelSeqNum);
        //通道调用序号
        payOrderInfo.setDstCallIndex(dstCallIndex);
        //通道交易码
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setPayeeAcctInfo(mchntAcctInfo.getSettleAcctNo());
        payOrderInfo.setPayeeAcctType(mchntAcctInfo.getSettleAcctType());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        payOrderInfo.setPayType("*");
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        return payOrderInfo;
    }

    private PayOrderInfo initEsbPayOrderInfo(MchntOrderInfo mchntOrderInfo, String payType,
                                             RoleAcctInfo roleAcctInfo,
                                             MchntAcctInfo mchntAcctInfo) throws Exception {
        String txnNum = BspsPayTypeEnum.BANK_CARD_PAY.getPayType().equals(payType) ? "00010000175500" :
                "01210000810101";

        Optional<ChannelCallCfg> channelCallCfgOptional = txnInfo.getChannelCallCfgList().stream().filter(item ->
                txnNum.equals(item.getCallChannelTxn())).findFirst();

        if (!channelCallCfgOptional.isPresent()) {
            rglog.error("通道服务调用配置表无ESB的数据！,sysSeqNum:<{}>,",
                    mchntOrderInfo.getSysSeqNum());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        //获取通道服务调用配置
        ChannelCallCfg channelCallCfg = channelCallCfgOptional.get();

        PayOrderInfo payOrderInfo = new PayOrderInfo();
        ConvertUtil.convertOutput(payOrderInfo);
        payOrderInfo.setSysSeqNum(mchntOrderInfo.getSysSeqNum());
        payOrderInfo.setMchntOrderId(mchntOrderInfo.getSysSeqNum());
        payOrderInfo.setOrderAmt(mchntOrderInfo.getOrderAmt());
        //实际清算给商户的金额
        payOrderInfo.setRealPayAmt(mchntOrderInfo.getMchntSettleAmt());
        //交易通道标识,本行ESB/他行IBPS
        String msgDstId = BspsPayTypeEnum.BANK_CARD_PAY.getPayType().equals(payType) ? "ESB" : "IBPS";
        payOrderInfo.setMsgDstId(msgDstId);
        String channelBizType = BspsPayTypeEnum.BANK_CARD_PAY.getPayType().equals(payType) ? BspsAppParamConstant.ONE_BANK_CASH_WITHDRAWAL_BIZ_TYPE : BspsAppParamConstant.OTHER_BANK_CASH_WITHDRAWAL_BIZ_TYPE;
        payOrderInfo.setChannelBizType(channelBizType);
        //调用ESB时，若ESB的后端系统能够返回通道的流水号，则记通道的流水号，若不能返回则登记调用ESB的流水号
        payOrderInfo.setChannelSeqNum(GlobalEsbUtil.generateEsbSeqeuenceNumber(mchntOrderInfo.getInstId()));
        //调用ESB时，填写生成的ESB流水号，生成规则为：系统流水号SYS_SEQ_NUM + 通道调用序号DST_CALL_INDEX的后19位
        payOrderInfo.setChannelReconKey(payOrderInfo.getChannelSeqNum());

        payOrderInfo.setDstCallIndex(channelCallCfg.getCallIndex());
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setPayType(payType);

        //付款方账户类型  - 本行内部户
        payOrderInfo.setPayerAcctType(AcctTypeEnum.BANK_ACCT.getAcctType());
        //付款方账户信息 - 机构内部户
        payOrderInfo.setPayerAcctInfo(roleAcctInfo.getActualAcct());
        //付款方 信息
        AcctInfo payerAcctInfo = new AcctInfo();
        payerAcctInfo.setAcctNo(roleAcctInfo.getActualAcct());
        payerAcctInfo.setAcctName(roleAcctInfo.getSettleAcctName());
        payerAcctInfo.setAcctType(AcctTypeEnum.BANK_ACCT.getAcctType());
//        payerAcctInfo.setAcctBankNo(roleAcctInfo.getRoleId());
//        payerAcctInfo.setAcctBankName(roleAcctInfo.getRoleId());
        payOrderInfo.setPayerRemark(JSONObject.toJSONString(payerAcctInfo));

        //收款方账户类型  - 商户的结算账户类型  不需要收款方账户类型
        payOrderInfo.setPayeeAcctType(mchntAcctInfo.getSettleAcctType());
        //收款方账户信息
        payOrderInfo.setPayeeAcctInfo(mchntAcctInfo.getSettleAcctNo());
        //收款方(商户) 户名 + 开户行行号
        AcctInfo payeeAcctInfo = new AcctInfo();
        payeeAcctInfo.setAcctNo(mchntAcctInfo.getSettleAcctNo());
        payeeAcctInfo.setAcctName(mchntAcctInfo.getSettleAcctName());
        //不需要收款方账户类型
        payeeAcctInfo.setAcctType(mchntAcctInfo.getSettleAcctType());
        payeeAcctInfo.setAcctBankNo(mchntAcctInfo.getAcctOpenBankNo());
        payeeAcctInfo.setAcctBankName(mchntAcctInfo.getAcctOpenBankName());
        payOrderInfo.setPayeeRemark(JSONObject.toJSONString(payeeAcctInfo));
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
        return payOrderInfo;
    }

    private MchntOrderInfo initMchntOrderInfo(MchntCashWithdrawalRequest request, XmlTreeUtil xmlTreeUtil, String oriOrderAmt, String mchntFee, String acctAvailableBalance) throws Exception {
        /* 商户结算净额(虚拟账户预授权金额) */
        String mchntSettleAmt;
        /* 实际结算本金 */
        String realSettleAmt;
        /* 当前 可用余额 > 手续费+提现金额    */
        /* 实际结算金额(虚拟账户预授权金额) =   手续费 + 提现金额 */
        realSettleAmt = AmountUtil.addition(request.getOrderAmt(), mchntFee);
        /* 商户结算净额 = 提现金额 */
        mchntSettleAmt = request.getOrderAmt();

        MchntOrderInfo mchntOrderInfo = new MchntOrderInfo();
        ConvertUtil.convertOutput(mchntOrderInfo);
        mchntOrderInfo.setTxnDate(request.getHeader().getTransDate());
        mchntOrderInfo.setTxnTime(request.getHeader().getTransTime());
        mchntOrderInfo.setUserId(request.getUserId());
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(mchntOrderInfo.getInstId(), mchntOrderInfo.getMchntNo());
        if (null == mchntInfo) {
            rglog.error("获取商户信息失败,mchntNo:<{}>", mchntOrderInfo.getMchntNo());
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);

        //基础公共
        mchntOrderInfo.setBizProdCode(BaseProdEnum.BASIC.getProdCode());
        mchntOrderInfo.setSysSeqNum(sysSeqNum);
        mchntOrderInfo.setMchntOrderId(sysSeqNum);
        mchntOrderInfo.setAcqInstCode(mchntInfo.getSignInstId());
        mchntOrderInfo.setIndustryType(mchntInfo.getIndustryType());
        mchntOrderInfo.setMchntNo(request.getMchntNo());
        mchntOrderInfo.setMchntName(mchntInfo.getMchntName());
        mchntOrderInfo.setOrderAmt(oriOrderAmt);
        //实际清算金额
        String feeRate = xmlTreeUtil.getXmlTreeStringValue("feeRate");
        mchntOrderInfo.setRealSettleAmt(realSettleAmt);
        mchntOrderInfo.setMchntSettleAmt(mchntSettleAmt);
        mchntOrderInfo.setMchntFee(mchntFee);
        mchntOrderInfo.setRealMchntFee(mchntFee);
        mchntOrderInfo.setFeeRate(feeRate);
        mchntOrderInfo.setVirtualAcctBalance(acctAvailableBalance);
        mchntOrderInfo.setMchntDiscountFee("0.00");

        mchntOrderInfo.setRealSettleFlag(mchntInfo.getRealSettleFlag());
        mchntOrderInfo.setCreateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
        mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        mchntOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        return mchntOrderInfo;
    }

    /**
     * 初始化用户订单信息
     *
     * @param request   请求
     * @param orderAmt  订单金额
     * @param sysSeqNum 系统标识号
     * @return 用户订单信息
     * @throws Exception 异常
     */
    private UserOrderInfo initUserOrderInfo(MchntCashWithdrawalRequest request, String orderAmt, String sysSeqNum) throws Exception {
        Header header = request.getHeader();
        UserOrderInfo userOrderInfo = new UserOrderInfo();
        ConvertUtil.convertOutput(userOrderInfo);
        userOrderInfo.setUserId(request.getUserId());
        userOrderInfo.setSysSeqNum(sysSeqNum);
        userOrderInfo.setFrontSeqNum(header.getTraceNo());
        userOrderInfo.setMsgSrcId(header.getSrcSysId());
        userOrderInfo.setTxnNum(header.getTxnNum());
        userOrderInfo.setTxnDate(header.getTransDate());
        userOrderInfo.setTxnTime(header.getTransTime());
        userOrderInfo.setTransChannelId(header.getChanlId());
        userOrderInfo.setMchntOrderId(sysSeqNum);
        userOrderInfo.setOrderAmt(orderAmt);
        userOrderInfo.setNeedPayAmt(orderAmt);
        userOrderInfo.setRealPayAmt(request.getOrderAmt());

        Date date = new Date();
        String currentDateTime = DateUtil.getDateByTimeStamp(date.getTime(), "yyyyMMddhhmmss");
        String orderExpiryTime = TimeUtil.calcDays(currentDateTime, BspsAppParamConstant.ORDER_EXPIRY_TIME);
        userOrderInfo.setOrderCreateTime(currentDateTime);
        userOrderInfo.setOrderExpiryTime(orderExpiryTime);
        userOrderInfo.setOrderStatus(OrderStatusEnum.INIT.getStatus());
        userOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        userOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        userOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));

        return userOrderInfo;
    }
    //endregion

    /**
     * 查询虚拟账户余额
     */
    private VirtAcctBalanceQueryResponse queryVirtAcctBalance(MchntCashWithdrawalRequest mchntCashWithdrawalRequest) throws Exception {
        Optional<ChannelCallCfg> channelCallCfgOptional = txnInfo.getChannelCallCfgList().stream().filter(item -> "0".equals(item.getCallIndex())).findFirst();
        if (!channelCallCfgOptional.isPresent()) {
            rglog.error("通道服务调用配置表无序号为0的数据！,instId:<{}>,traceNo:<{}>,",
                    mchntCashWithdrawalRequest.getHeader().getInstId(), mchntCashWithdrawalRequest.getHeader().getTraceNo());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        //获取通道服务调用配置
        ChannelCallCfg channelCallCfg = channelCallCfgOptional.get();
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(mchntCashWithdrawalRequest.getHeader().getInstId(), mchntCashWithdrawalRequest.getMchntNo());
        if (null == mchntInfo) {
            rglog.error("获取商户信息失败,mchntNo:<{}>", mchntCashWithdrawalRequest.getMchntNo());
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }
        VirtAcctBalanceQueryRequest virtAcctBalanceQueryRequest = new VirtAcctBalanceQueryRequest();
        ConvertUtil.convertOutput(virtAcctBalanceQueryRequest);
        cc.rengu.igas.acct.facade.base.Header header = new cc.rengu.igas.acct.facade.base.Header();
        header.setInstId(mchntCashWithdrawalRequest.getHeader().getInstId());
        header.setTxnNum(channelCallCfg.getCallChannelTxn());
        header.setTraceNo(sysSeqNum + channelCallCfg.getCallIndex());
        header.setSrcSysId(AppParamConstant.SYS_ID);
        header.setChanlId(BspsAppParamConstant.BSP_SYS_ID);
        header.setTransTime(DateUtil.getCurrentTime());
        header.setTransDate(DateUtil.getCurrentDate());
        virtAcctBalanceQueryRequest.setHeader(header);
        //userType : 00-商户  01-会员 02-营销
        virtAcctBalanceQueryRequest.setUserType("00");
        // if (MchntTypeEnum.CHAIN_MCHNT_STORE.getMchntType().equals(mchntBaseInfo.getMchntType()) && BspsAppParamConstant.FLAG_N.equals(mchntBaseInfo.getIndependentDataFlag())) {
        //     //连锁商户门店非独立维护，填连锁商户号
        //     virtAcctBalanceQueryRequest.setUserId(mchntBaseInfo.getChainMchntNo());
        // } else {
        //     virtAcctBalanceQueryRequest.setUserId(mchntCashWithdrawalRequest.getMchntNo());
        // }
        virtAcctBalanceQueryRequest.setUserId(mchntCashWithdrawalRequest.getMchntNo());
        virtAcctBalanceQueryRequest.setAcctType("00");  //虚拟账户
        DubboService dubboService = new DubboServiceImpl();
        Result<VirtAcctBalanceQueryResponse> acctDubboResult = (Result<VirtAcctBalanceQueryResponse>) dubboService.callDubboService(DubboMethodConstant.DUBBO_VIRT_ACCT_SERVICE, "virtAcctBalanceQuery", virtAcctBalanceQueryRequest);
        if (null == acctDubboResult) {
            rglog.error("调用Dubbo查询虚拟账户余额失败,前端流水号：<{}>,mchntNo:<{}>",
                    mchntCashWithdrawalRequest.getHeader().getTraceNo(), mchntCashWithdrawalRequest.getMchntNo());
            throw new BizException(OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode(), OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespDesc());
        } else if (!acctDubboResult.isSuccess() || !BspsAppParamConstant.DUBBO_SUCCESS.equals(acctDubboResult.getResult().getRespCode())) {
            rglog.error("调用Dubbo查询虚拟账户余额失败，前端流水号：<{}>,mchntNo:<{}>",
                    mchntCashWithdrawalRequest.getHeader().getTraceNo(), mchntCashWithdrawalRequest.getMchntNo());
            throw new BizException(acctDubboResult.getResult().getRespCode(), acctDubboResult.getResult().getRespDesc());
        }
        // else if (AmountUtil.compare(acctDubboResult.getResult().getAvailableBalance(), mchntCashWithdrawalRequest.getOrderAmt()) == -1) {
        //     /* 若可用余额 < 提现金额 则返回提现失败 */
        //     rglog.error("可用余额小于提现金额，提现失败！前端流水号：<{}>,mchntNo:<{}>", mchntCashWithdrawalRequest.getHeader().getTraceNo(), mchntCashWithdrawalRequest.getMchntNo());
        //     throw new BizException(RespCodeEnum.WITHDRAWAL_AMT_OVER_LIMIT.getRespCode(), RespCodeEnum.WITHDRAWAL_AMT_OVER_LIMIT.getRespDesc());
        // }

        return acctDubboResult.getResult();
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        MchntCashWithdrawalResponse mchntCashWithdrawalResponse = (MchntCashWithdrawalResponse) bizResponse.getResult();
        ConvertUtil.convertInput(mchntCashWithdrawalResponse);
    }

    /**
     * 调用虚拟账户接口进行预授权处理
     */
    private void acctPreAuth(MchntCashWithdrawalRequest mchntCashWithdrawalRequest, String sysSeqNum,
                             UserOrderInfo userOrderInfo,
                             MchntOrderInfo mchntOrderInfo, PayOrderInfo virtPreAuthPayOrderInfo) throws Exception {
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(mchntCashWithdrawalRequest.getHeader().getInstId(), mchntCashWithdrawalRequest.getMchntNo());
        if (null == mchntInfo) {
            rglog.error("获取商户信息失败,mchntNo:<{}>", mchntCashWithdrawalRequest.getMchntNo());
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }
        OrderService orderService = new OrderServiceImpl();
        VirtAcctPreAuthRequest virtAcctPreAuthRequest = new VirtAcctPreAuthRequest();
        ConvertUtil.convertOutput(virtAcctPreAuthRequest);
        BeanUtil.beanCopy(virtPreAuthPayOrderInfo, virtAcctPreAuthRequest);
        cc.rengu.igas.acct.facade.base.Header header = virtAcctPreAuthRequest.getHeader();
        header.setInstId(mchntCashWithdrawalRequest.getHeader().getInstId());
        header.setSrcSysId(AppParamConstant.SYS_ID);
        header.setChanlId(BspsAppParamConstant.BSP_SYS_ID);
        header.setTransTime(DateUtil.getCurrentTime());
        header.setTransDate(DateUtil.getCurrentDate());
        virtAcctPreAuthRequest.setAcctType("00");  //虚拟账户

        header.setTraceNo(virtPreAuthPayOrderInfo.getChannelSeqNum());
        header.setTxnNum(virtPreAuthPayOrderInfo.getDstTxnNum());
        //userType : 00-商户  01-会员 02-营销
        virtAcctPreAuthRequest.setUserType("00");
        virtAcctPreAuthRequest.setTransAmt(virtPreAuthPayOrderInfo.getRealPayAmt());
        if (MchntTypeEnum.CHAIN_MCHNT_STORE.getMchntType().equals(mchntInfo.getMchntType()) && BspsAppParamConstant.FLAG_N.equals(mchntInfo.getIndependentDataFlag())) {
            //连锁商户门店非独立维护,填连锁商户号
            virtAcctPreAuthRequest.setUserId(mchntInfo.getChainMchntNo());
        } else {
            virtAcctPreAuthRequest.setUserId(mchntOrderInfo.getMchntNo());
        }
        virtAcctPreAuthRequest.setHeader(header);
        DubboService dubboService = new DubboServiceImpl();
        Result<VirtAcctPreAuthResponse> acctDubboResult = (Result<VirtAcctPreAuthResponse>) dubboService.callDubboService(DubboMethodConstant.DUBBO_VIRT_ACCT_SERVICE, "virtAcctPreAuth", virtAcctPreAuthRequest);
        if (null == acctDubboResult || !acctDubboResult.isSuccess() ||
                !BspsAppParamConstant.DUBBO_SUCCESS.equals(acctDubboResult.getResult().getRespCode()) || !"00".equals(acctDubboResult.getResult().getTransStatus())) {
            rglog.error("调用Dubbo虚拟账户预授权失败！dubboResult:<{}>，前端流水号：<{}>,mchntNo:<{}>",
                    JSONObject.toJSONString(acctDubboResult), mchntCashWithdrawalRequest.getHeader().getTraceNo(), mchntCashWithdrawalRequest.getMchntNo());
            //更新所有订单表为失败
            userOrderInfo.setOrderStatus(OrderStatusEnum.CLOSE.getStatus());
            userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
            userOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            mchntOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
            mchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            virtPreAuthPayOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
            virtPreAuthPayOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            virtPreAuthPayOrderInfo.setSettleDate(null == acctDubboResult ? null : acctDubboResult.getResult().getAcctDate());
            virtPreAuthPayOrderInfo.setRespCode(null == acctDubboResult ? null : acctDubboResult.getResult().getRespCode());
            virtPreAuthPayOrderInfo.setRespDesc(null == acctDubboResult ? null : acctDubboResult.getResult().getRespDesc());
            boolean dbResult = orderService.updateOrderInfo(userOrderInfo, Arrays.asList(mchntOrderInfo), virtPreAuthPayOrderInfo);
            if (!dbResult) {
                rglog.error("更新用户订单，商户订单，支付订单状态为失败的数据库操作失败！instId:<{}>，sysSeqNum：<{}>",
                        mchntCashWithdrawalRequest.getHeader().getInstId(), sysSeqNum);
                throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
            }
            throw new BizException(acctDubboResult.getResult().getRespCode(), acctDubboResult.getResult().getRespDesc());
        } else {
            //更新 虚拟账户预授权-支付订单为成功
            virtPreAuthPayOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            virtPreAuthPayOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
            virtPreAuthPayOrderInfo.setRespCode(acctDubboResult.getResult().getRespCode());
            virtPreAuthPayOrderInfo.setRespDesc(acctDubboResult.getResult().getRespDesc());
            virtPreAuthPayOrderInfo.setSettleDate(acctDubboResult.getResult().getAcctDate());
            //冻结记账流水号
            virtPreAuthPayOrderInfo.setChannelOrderId(acctDubboResult.getResult().getAcctSeqNum());
            virtPreAuthPayOrderInfo.setChannelSeqNum(acctDubboResult.getResult().getAcctSeqNum());
            //商户虚拟账户余额
            mchntOrderInfo.setVirtualAcctBalance(acctDubboResult.getResult().getAfterAvailableBalance());
            boolean dbResult = orderService.updateOrderInfo(null, Arrays.asList(mchntOrderInfo), virtPreAuthPayOrderInfo);
            if (!dbResult) {
                rglog.error("更新虚拟账户预授权-支付订单状态为成功的数据库操作失败！instId:<{}>，sysSeqNum：<{}>",
                        mchntCashWithdrawalRequest.getHeader().getInstId(), sysSeqNum);
                throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
            }
        }
    }

    /**
     * 提现
     */
    private BizResponse mchntCash(MchntCashWithdrawalRequest mchntCashWithdrawalRequest, UserOrderInfo userOrderInfo, MchntOrderInfo mchntOrderInfo, PayOrderInfo esbCashPayOrderInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        BizResponse<MchntCashWithdrawalResponse> bizResponse = new BizResponse<>();
        MchntCashWithdrawalResponse mchntCashWithdrawalResponse = new MchntCashWithdrawalResponse();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);

        String resultCode = null;
        String esbMsg = null;
        String esbChannelTraceNo = esbCashPayOrderInfo.getChannelSeqNum();
        String settleDate = esbCashPayOrderInfo.getSettleDate();
        OrderService orderService = new OrderServiceImpl();
        //TODO 调用 由项目组实现提现交易
        // （1） 调用本行卡/他行卡提现接口

        boolean dbResult = false;
        if (BspsAppParamConstant.DUBBO_OVERTIME.equals(resultCode)) {
            rglog.error("调用Dubbo ESB进行提现超时！，sysSeqNum：<{}>,mchntNo:<{}>", mchntOrderInfo.getSysSeqNum(), mchntOrderInfo.getMchntNo());
            //更新用户，商户，支付（ESB）订单表为失败
            userOrderInfo.setTransStatus(TransStatusEnum.TRANS_TIMEOUT.getStatus());
            userOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
            mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_TIMEOUT.getStatus());
            mchntOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
            esbCashPayOrderInfo.setTransStatus(TransStatusEnum.TRANS_TIMEOUT.getStatus());
            esbCashPayOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
            dbResult = orderService.updateOrderInfo(userOrderInfo, Arrays.asList(mchntOrderInfo), esbCashPayOrderInfo);
            if (!dbResult) {
                rglog.error("更新用户订单，商户订单，支付订单状态为超时的数据库操作失败！instId:<{}>，sysSeqNum：<{}>",
                        mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
            }

            mchntCashWithdrawalResponse.setRespCode(RespCodeEnum.TRANS_IN_PROGRESS.getRespCode());
            mchntCashWithdrawalResponse.setRespDesc(RespCodeEnum.TRANS_IN_PROGRESS.getRespDesc());
            bizResponse.setRspSysId(BspsAppParamConstant.SYS_ID);
            bizResponse.setResult(mchntCashWithdrawalResponse);
            bizResponse.setRespCode(mchntCashWithdrawalResponse.getRespCode());
            bizResponse.setRespDesc(mchntCashWithdrawalResponse.getRespDesc());
            return bizResponse;
        } else if (BspsAppParamConstant.DUBBO_SUCCESS.equals(resultCode)) {
            //更新 ESB提现-支付订单为成功
            userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
            userOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            userOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
            mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            mchntOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
            esbCashPayOrderInfo.setChannelSeqNum(esbChannelTraceNo);
            esbCashPayOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            esbCashPayOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
            esbCashPayOrderInfo.setSettleDate(settleDate);
            esbCashPayOrderInfo.setRespCode(resultCode);
            esbCashPayOrderInfo.setRespDesc(esbMsg);
            dbResult = orderService.updateOrderInfo(userOrderInfo, Arrays.asList(mchntOrderInfo), esbCashPayOrderInfo);
            if (!dbResult) {
                rglog.error("更新ESB提现-支付订单状态为成功的数据库操作失败！instId:<{}>，sysSeqNum：<{}>",
                        mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
            }
            /* 异步进行预授权完成 */
            invokeSuccessHandle(userOrderInfo, mchntOrderInfo, esbCashPayOrderInfo);
            mchntCashWithdrawalResponse.setMchntFee(mchntOrderInfo.getMchntFee());
            mchntCashWithdrawalResponse.setAcctBalance(mchntOrderInfo.getVirtualAcctBalance());
            mchntCashWithdrawalResponse.setRealSettleAmt(mchntOrderInfo.getMchntSettleAmt());
            mchntCashWithdrawalResponse.setSysSeqNum(sysSeqNum);

        } else {
            //更新 ESB提现-支付订单为失败， 进行预授权撤销
            userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
            userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
            userOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            mchntOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
            mchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
//            esbCashPayOrderInfo.setChannelReconKey(esbChannelReconKey);
            esbCashPayOrderInfo.setChannelSeqNum(esbChannelTraceNo);
            esbCashPayOrderInfo.setSettleDate(settleDate);
            esbCashPayOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
            esbCashPayOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            esbCashPayOrderInfo.setRespCode(resultCode);
            esbCashPayOrderInfo.setRespDesc(esbMsg);
            dbResult = orderService.updateOrderInfo(userOrderInfo, Arrays.asList(mchntOrderInfo), esbCashPayOrderInfo);
            if (!dbResult) {
                rglog.error("更新ESB提现-支付订单状态为成功的数据库操作失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
            }
            /* 异步进行预授权撤销 */
            invokeSuccessHandle(userOrderInfo, mchntOrderInfo, esbCashPayOrderInfo);
            mchntCashWithdrawalResponse.setRespCode(resultCode);
            mchntCashWithdrawalResponse.setRespDesc(esbMsg);
            bizResponse.setRspSysId(BspsAppParamConstant.SYS_ID);
            bizResponse.setResult(mchntCashWithdrawalResponse);
            bizResponse.setRespCode(mchntCashWithdrawalResponse.getRespCode());
            bizResponse.setRespDesc(mchntCashWithdrawalResponse.getRespDesc());
            return bizResponse;

        }

        bizResponse.setResult(mchntCashWithdrawalResponse);
        bizResponse.setRspSysId(BspsAppParamConstant.SYS_ID);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        return bizResponse;
    }

    private void invokeSuccessHandle(UserOrderInfo userOrderInfo, MchntOrderInfo mchntOrderInfo, PayOrderInfo payOrderInfo) throws Exception {
        TransSuccessHandleService transSuccessHandleService = new TransSuccessHandleServiceImpl();
        transSuccessHandleService.virtAcctMchntAujustByPreCompOrPreCancel(userOrderInfo, mchntOrderInfo, payOrderInfo);
    }
}
